﻿#include "IntelHexParser.h"
#include <QStringList>

IntelHexParser::IntelHexParser(const QString &src)
    : m_src(src)
{
}

QString IntelHexParser::errorString() const
{
    return m_error;
}

QList<MemBlock> IntelHexParser::memory() const
{
    return m_memory;
}

quint32 IntelHexParser::startSegmentAddr() const
{
    return m_startSegmentAddr;
}

quint32 IntelHexParser::startLinearAddr() const
{
    return m_startLinearAddr;
}

QByteArray IntelHexParser::toContiguousImage(quint32 &baseAddr, quint8 fill) const
{
    if (m_memory.isEmpty()) {
        baseAddr = 0;
        return QByteArray();
    }

    // 1. 找最小、最大地址
    quint32 minAddr = m_memory.first().addr;
    quint32 maxAddr = m_memory.first().addr + m_memory.first().data.size();

    for (const MemBlock &blk : m_memory) {
        if (blk.addr < minAddr)
            minAddr = blk.addr;
        quint32 end = blk.addr + blk.data.size();
        if (end > maxAddr)
            maxAddr = end;
    }

    // 2. 分配完整缓冲区
    quint32 size = maxAddr - minAddr;
    QByteArray image(size, (char)fill);

    // 3. 拷贝数据
    for (const MemBlock &blk : m_memory) {
        int offset = blk.addr - minAddr;
        for (int i = 0; i < blk.data.size(); ++i) {
            image[offset + i] = blk.data[i];
        }
    }

    baseAddr = minAddr;
    return image;
}

void IntelHexParser::addData(quint32 addr, const QByteArray &data)
{
    // 合并连续块
    if (!m_memory.isEmpty()) {
        MemBlock &last = m_memory.last();
        quint32 lastEnd = last.addr + last.data.size();
        if (lastEnd == addr) {
            last.data.append(data);
            return;
        }
    }
    // 新建块
    MemBlock blk{addr, data};
    m_memory.append(blk);
}

bool IntelHexParser::parse()
{
    m_memory.clear();
    m_error.clear();
    m_startSegmentAddr = 0;
    m_startLinearAddr = 0;

    QStringList lines = m_src.split('\n', Qt::SkipEmptyParts);

    quint32 upperAddr = 0;
    quint32 segmentAddr = 0;

    for (int lineNum = 0; lineNum < lines.size(); ++lineNum) {
        QString line = lines[lineNum].trimmed();
        if (line.isEmpty()) continue;

        if (!line.startsWith(':')) {
            m_error = QObject::tr("Line %1: Missing ':' at start").arg(lineNum + 1);
            return false;
        }

        QByteArray hex = line.mid(1).toLatin1();
        if (hex.size() < 10) {
            m_error = QObject::tr("Line %1: Too short").arg(lineNum + 1);
            return false;
        }

        bool ok = false;
        int len = hex.mid(0, 2).toInt(&ok, 16);
        if (!ok) {
            m_error = QObject::tr("Line %1: Invalid length").arg(lineNum + 1);
            return false;
        }

        quint16 addr = hex.mid(2, 4).toInt(&ok, 16);
        if (!ok) {
            m_error = QObject::tr("Line %1: Invalid address").arg(lineNum + 1);
            return false;
        }

        int rectype = hex.mid(6, 2).toInt(&ok, 16);
        if (!ok) {
            m_error = QObject::tr("Line %1: Invalid record type").arg(lineNum + 1);
            return false;
        }

        QByteArray data;
        for (int i = 0; i < len; ++i) {
            int idx = 8 + i * 2;
            if (idx + 2 > hex.size()) {
                m_error = QObject::tr("Line %1: Data too short").arg(lineNum + 1);
                return false;
            }
            char c = (char)hex.mid(idx, 2).toInt(&ok, 16);
            if (!ok) {
                m_error = QObject::tr("Line %1: Invalid data byte").arg(lineNum + 1);
                return false;
            }
            data.append(c);
        }

        int checksumIndex = 8 + len * 2;
        if (checksumIndex + 2 > hex.size()) {
            m_error = QObject::tr("Line %1: Missing checksum").arg(lineNum + 1);
            return false;
        }

        quint8 checksum = hex.mid(checksumIndex, 2).toInt(&ok, 16);
        if (!ok) {
            m_error = QObject::tr("Line %1: Invalid checksum").arg(lineNum + 1);
            return false;
        }

        // 校验和计算
        QByteArray bytes;
        bytes.append((char)len);
        bytes.append((char)(addr >> 8));
        bytes.append((char)(addr & 0xFF));
        bytes.append((char)rectype);
        bytes.append(data);

        quint32 sum = 0;
        for (auto c : bytes)
            sum += (quint8)c;
        sum += checksum;

        if ((sum & 0xFF) != 0) {
            m_error = QObject::tr("Line %1: Checksum error").arg(lineNum + 1);
            return false;
        }

        // 处理记录类型
        switch (rectype) {
        case 0x00: { // 数据记录
            quint32 fullAddr = (upperAddr << 16) + (segmentAddr << 4) + addr;
            addData(fullAddr, data);
            break;
        }
        case 0x01: // 文件结束
            // nothing special
            break;
        case 0x02: // 扩展段地址
            if (data.size() != 2) {
                m_error = QObject::tr("Line %1: Invalid extended segment address size").arg(lineNum + 1);
                return false;
            }
            segmentAddr = ((quint8)data[0] << 8 | (quint8)data[1]);
            upperAddr = 0;
            break;
        case 0x04: // 扩展线性地址
            if (data.size() != 2) {
                m_error = QObject::tr("Line %1: Invalid extended linear address size").arg(lineNum + 1);
                return false;
            }
            upperAddr = ((quint8)data[0] << 8 | (quint8)data[1]);
            segmentAddr = 0;
            break;
        case 0x03: // 起始段地址
            if (data.size() != 4) {
                m_error = QObject::tr("Line %1: Invalid start segment address size").arg(lineNum + 1);
                return false;
            }
            m_startSegmentAddr = ((quint8)data[0] << 24) |
                                 ((quint8)data[1] << 16) |
                                 ((quint8)data[2] << 8) |
                                 ((quint8)data[3]);
            break;
        case 0x05: // 起始线性地址
            if (data.size() != 4) {
                m_error = QObject::tr("Line %1: Invalid start linear address size").arg(lineNum + 1);
                return false;
            }
            m_startLinearAddr = ((quint8)data[0] << 24) |
                                ((quint8)data[1] << 16) |
                                ((quint8)data[2] << 8) |
                                ((quint8)data[3]);
            break;
        default:
            // 未知类型，不报错，忽略
            break;
        }
    }

    return true;
}
